package server

import (
	"embed"
	"fmt"
	cmdutils "github.com/MzoroHaHa/dev-tools/backend/app/cmd-utils"
	"github.com/MzoroHaHa/dev-tools/backend/app/logger"
	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"
	"text/template"
	"time"
)

var lsLogger = logger.NewLogger("local-server")

type LocalServer struct {
	Port        uint
	BindAddress string
	engine      *gin.Engine
}

const staticUri = "/dt"
const runtimeUri = "/runtime"

var staticPath = staticUri + "/*filepath"
var runtimePath = runtimeUri + "/*filepath"

var UsingServer *LocalServer

//go:embed dt
var content embed.FS

//go:embed runtime
var runtimeContent embed.FS

func (ls *LocalServer) String() string {
	return fmt.Sprintf("Port: %d, BindAddress: %s", ls.Port, ls.BindAddress)
}

func (ls *LocalServer) GetAddr() string {
	return fmt.Sprintf("%s:%d", ls.BindAddress, ls.Port)
}

func (ls *LocalServer) GetStaticUrl() string {
	return fmt.Sprintf("http://%s%s", ls.GetAddr(), staticUri)
}

func (ls *LocalServer) InitGin() {
	if UsingServer != nil {
		panic("Server already initialized.")
	}
	// 跨域问题
	allowOrigins := cmdutils.GetAllowOrigin()
	allowOriginsArr := make([]string, 0)
	if len(allowOrigins) != 0 {
		allowOriginsArr = strings.Split(allowOrigins, ",")
	}
	gin.SetMode(gin.ReleaseMode)
	ls.engine = gin.New(func(engine *gin.Engine) {
		engine.Use(gin.Logger(),
			gin.Recovery())
		if len(allowOriginsArr) != 0 {
			engine.Use(cors.New(cors.Config{
				AllowOrigins:     allowOriginsArr,
				AllowMethods:     []string{"*"},
				AllowHeaders:     []string{"*"},
				ExposeHeaders:    []string{"Content-Length"},
				AllowCredentials: true,
				MaxAge:           12 * time.Hour,
			}))
		}
	})
	// embed fs gin需要特殊处理
	ls.engine.GET(staticPath, func(c *gin.Context) {
		c.FileFromFS(c.Request.URL.Path, http.FS(content))
	})

	runtimeTmpl := template.New("")
	runtimeTmpl, err := runtimeTmpl.ParseFS(runtimeContent, "**/*.tmpl")
	if err != nil {
		panic(err)
	}
	// runtime js
	ls.engine.GET(runtimePath, func(c *gin.Context) {
		c.Writer.Header().Add("Content-Type", "application/javascript")
		c.Writer.WriteHeader(http.StatusOK)
		var data any
		data = map[string]interface{}{}
		if strings.Compare(cmdutils.GetRuntimeBaseJs(), c.Request.URL.Path) == 0 {
			data = map[string]interface{}{
				"ApiBase": "http://" + ls.GetAddr(),
			}
		}
		_t := runtimeTmpl.Lookup(c.Request.URL.Path)
		if _t == nil {
			c.Status(http.StatusNotFound)
			_, _ = c.Writer.Write([]byte(c.Request.URL.Path + " not found."))
			return
		}
		_ = _t.Execute(c.Writer, data)
	})

	UsingServer = ls
	// 其他routes
	InitRoutes()
}

func (ls *LocalServer) Start() {
	go func() {
		// TODO 需要知道启动是否成功， 是否能顺利停下
		lsLogger.Info("Starting server", "at", ls.GetAddr())
		_ = ls.engine.Run(ls.GetAddr())
		lsLogger.Info("Stopped server", "at", ls.GetAddr())
	}()
}

func (ls *LocalServer) Stop() {
}
